from math import sqrt
import abc


class MyMath:
    """
    把昨天封装的Math类中的实例方法改为静态方法, 体会一下两者的区别
    """

    # ***总结：通过staticmethod装饰器装饰
    # 什么时候用到？如果一个类中的方法本身就是很抽象的概念的时候，其实是不需要实例化的，这时候用静态方法，类直接调用
    # 静态方法：常用来对抽象的概念进行一个归类的作用
    def __init__(self):
        print('__init__called')

    # 加法addition
    @staticmethod
    def add(*args):
        res = 0
        for i in range(len(args)):
            res += args[i]
        return res

    # 减法subtraction
    @staticmethod
    def sub(*args):
        res = args[0]
        for i in range(1, len(args)):
            res -= args[i]
        return res

    # 乘法multiplication
    @staticmethod
    def mul(*args):
        res = args[0]
        for i in range(1, len(args)):
            res *= args[i]
        return res

    # 除法division
    @staticmethod
    def div(*args):
        res = args[0]
        for i in range(1, len(args)):
            assert args[i] != 0
            res /= args[i]
        return res

    # 整除
    @staticmethod
    def div_z(*args):
        res = args[0]
        for i in range(1, len(args)):
            assert args[i] != 0
            res //= args[i]
        return res

    # 取余remainder
    @staticmethod
    def rem(*args):
        res = args[0]
        for i in range(1, len(args)):
            res %= args[i]
        return res

    # 乘方Power
    @staticmethod
    def pow(*args):
        res = args[0]
        for i in range(1, len(args)):
            res **= args[i]
        return res

    # 开方Square root
    @staticmethod
    def sqr(x):
        return sqrt(x)


# 自定义基类
class ProgramingLanguage(abc.ABC):
    # 类私有属性
    __rank_list = {"C": 1, "Python": 2, "Java": 3, "C++": 4, "C#": 5}
    #  类属性
    total = 50

    @abc.abstractmethod
    def __init__(self):
        print('__init__ called')

    # 类方法，隐藏内部的细节，对外暴露 get_rank 的接口
    @classmethod
    def get_rank(cls):
        return cls.__rank_list


class Python(ProgramingLanguage):
    data_type = ["Int（整数）", "Float（浮点数）", "String（字符串）",
                 "Boolean（布尔值）", "None（空）", "Bytes（字节）"]
    data_structure = ["set", "list", "dict", "tuple"]
    # 私有属性
    __founder = 'Guido'

    def __init__(self, name):
        super(Python, self).__init__()
        self.name = name
        self.__rank = 2

    # 类方法，隐藏内部的细节，对外暴露 get_founder 的接口
    @classmethod
    def get_founder(cls):
        return cls.__founder

    def can_do(self):
        return '{}能做web应用开发、网络爬虫、AI人工智能与数据科学、数据分析！'.format(self.name)


class Java(ProgramingLanguage):
    # 私有属性
    __founder = 'James Gosling'

    def __init__(self, name):
        super(Java, self).__init__()
        self.name = name
        self.__rank = 3

    # 自定义__str__
    def __str__(self):
        return '自定义__str__接口'

    # 类方法，隐藏内部的细节，对外暴露 get_founder 的接口
    @classmethod
    def get_founder(cls):
        return cls.__founder

    def can_do(self):
        return '{}能开发网站，Android应用，PC端，游戏等'.format(self.name)


if __name__ == '__main__':
    res_add = MyMath.add(1, 2, 2)
    print(res_add)
    res_sub = MyMath.sub(1, 2, 2)
    print(res_sub)
    res_mul = MyMath.mul(1, 2, 2)
    print(res_mul)
    res_div = MyMath.div(1, 2, 2)
    print(res_div)
    res_div_z = MyMath.div_z(1, 2, 2)
    print(res_div_z)
    res_rem = MyMath.rem(1, 2, 1)
    print(res_rem)
    res_pow = MyMath.pow(2, 3, 2)
    print(res_pow)
    res_sqr = MyMath.sqr(3)
    print(res_sqr)

    python = Python('Python')
    print(f'访问类的私有属性：{Python.get_founder()}')
    print(f'访问实例的方法：{python.can_do()}')
    var = Python.data_type
    print(f'var:{var}')
    print(f'访问父类的属性：{python.total}')
    print(f'访问父类的私有属性：{ProgramingLanguage.get_rank()}')

    java = Java('Java')
    print(f'访问类的私有属性：{Java.get_founder()}')
    print(f'访问实例的方法：{java.can_do()}')
    print(f'访问父类的属性：{java.total}')
    print(java.__str__())
    print(f'访问父类的方法：{ProgramingLanguage.get_rank()}')
